home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / pinfocom_3_0.lha / Source / amiga_game.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  23KB  |  1,044 lines

  1. /* amiga_game.c
  2.  *
  3.  *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
  4.  *  Copyright (C) 1987-1992  InfoTaskForce
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to the
  18.  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /*
  22.  * $Header: RCS/amiga_game.c,v 3.0 1992/10/21 16:56:19 pds Stab $
  23.  */
  24.  
  25. #ifndef _AMIGA_GLOBAL_H
  26. #include "amiga_global.h"
  27. #endif    /* !_AMIGA_GLOBAL_H */
  28.  
  29.     /* GameAdd(struct List *List,int Index,const char *FileName):
  30.      *
  31.      *    Add another game file to the list.
  32.      */
  33.  
  34. VOID
  35. GameAdd(struct List *List,int Index,const char *FileName)
  36. {
  37.     struct Node    *Node,
  38.             *Next;
  39.     Bool         GotIt = FALSE;
  40.     char        *Title = Titles[Index];
  41.  
  42.         /* In order to sort the list properly,
  43.          * invert the index counter.
  44.          */
  45.  
  46.     Index = NUM_GAMES - Index;
  47.  
  48.         /* Is this game already in the list? */
  49.  
  50.     Node = List -> lh_Head;
  51.  
  52.     while(Next = Node -> ln_Succ)
  53.     {
  54.         if(Node -> ln_Pri == Index)
  55.         {
  56.             GotIt = TRUE;
  57.  
  58.             break;
  59.         }
  60.         else
  61.             Node = Next;
  62.     }
  63.  
  64.         /* Is it? */
  65.  
  66.     if(!GotIt)
  67.     {
  68.         struct GameNode    *Node;
  69.         int         TitleLen;
  70.  
  71.             /* Determine length of game title. */
  72.  
  73.         TitleLen = strlen(Title) + 1;
  74.  
  75.             /* Allocate space for node, title and
  76.              * corresponding file name.
  77.              */
  78.  
  79.         if(Node = (struct GameNode *)AllocVec(sizeof(struct GameNode) + TitleLen + strlen(FileName) + 1,MEMF_ANY | MEMF_CLEAR))
  80.         {
  81.                 /* Set up the node contents. */
  82.  
  83.             Node -> gn_Node . ln_Name    = (char *)(Node + 1);
  84.             Node -> gn_Node . ln_Pri    = Index;
  85.             Node -> gn_FileName        = Node -> gn_Node . ln_Name + TitleLen;
  86.  
  87.                 /* Fill in the game title and the
  88.                  * corresponding file name.
  89.                  */
  90.  
  91.             strcpy(Node -> gn_Node . ln_Name,    Title);
  92.             strcpy(Node -> gn_FileName,        FileName);
  93.  
  94.                 /* Add the node to the list. */
  95.  
  96.             Enqueue(List,(struct Node *)Node);
  97.         }
  98.     }
  99. }
  100.  
  101.     /* GameMatch(const char *Name,const char *Pattern):
  102.      *
  103.      *    Test if a name matches a wildcard pattern.
  104.      */
  105.  
  106. Bool
  107. GameMatch(const char *Name,const char *Pattern)
  108. {
  109.     char MatchBuffer[MAX_FILENAME_LENGTH];
  110.  
  111.         /* Tokenize the pattern. */
  112.  
  113.     if(ParsePatternNoCase((STRPTR)Pattern,MatchBuffer,MAX_FILENAME_LENGTH) != -1)
  114.     {
  115.             /* Make the match. */
  116.  
  117.         if(MatchPatternNoCase(MatchBuffer,(STRPTR)Name))
  118.             return(TRUE);
  119.     }
  120.  
  121.     return(FALSE);
  122. }
  123.  
  124.     /* GameMultiScan(struct List *GameList,const char *Pattern):
  125.      *
  126.      *    Scan multi-volumne assignment for game files.
  127.      */
  128.  
  129. VOID
  130. GameMultiScan(struct List *GameList,const char *Pattern)
  131. {
  132.     struct DevProc        *DevProc    = NULL;
  133.     struct MsgPort        *FileSysTask    = GetFileSysTask();
  134.     struct FileInfoBlock    *FileInfo;
  135.     header_t         GameHeader;
  136.  
  137.         /* Allocate the fileinfo data. */
  138.  
  139.     if(FileInfo = (struct FileInfoBlock *)AllocDosObjectTags(DOS_FIB,TAG_DONE))
  140.     {
  141.             /* Loop until all assignments are
  142.              * processed.
  143.              */
  144.  
  145.         do
  146.         {
  147.                 /* Get the default filesystem task
  148.                  * in case we stumble upon NULL
  149.                  * directory locks.
  150.                  */
  151.  
  152.             if(DevProc = GetDeviceProc("Infocom:",DevProc))
  153.             {
  154.                     /* Set the default filesystem task. */
  155.  
  156.                 SetFileSysTask(DevProc -> dvp_Port);
  157.  
  158.                     /* Check the object type. */
  159.  
  160.                 if(Examine(DevProc -> dvp_Lock,FileInfo))
  161.                 {
  162.                         /* Is it really a directory? */
  163.  
  164.                     if(FileInfo -> fib_DirEntryType > 0)
  165.                     {
  166.                             /* Scan the directory... */
  167.  
  168.                         while(ExNext(DevProc -> dvp_Lock,FileInfo))
  169.                         {
  170.                                 /* Did we find a file? */
  171.  
  172.                             if(FileInfo -> fib_DirEntryType < 0)
  173.                             {
  174.                                     /* Does the name match the template? */
  175.  
  176.                                 if(GameMatch(FileInfo -> fib_FileName,Pattern))
  177.                                 {
  178.                                         /* Build full path name. */
  179.  
  180.                                     strcpy(TempBuffer,"Infocom:");
  181.  
  182.                                     if(AddPart(TempBuffer,FileInfo -> fib_FileName,MAX_FILENAME_LENGTH))
  183.                                     {
  184.                                         FILE *GameFile;
  185.  
  186.                                             /* Try to open the file for reading. */
  187.  
  188.                                         if(GameFile = fopen(TempBuffer,"rb"))
  189.                                         {
  190.                                                 /* Read the game file header. */
  191.  
  192.                                             if(fread(&GameHeader,sizeof(header_t),1,GameFile) == 1)
  193.                                             {
  194.                                                     /* Is it a type 3 game? */
  195.  
  196.                                                 if(GameHeader . z_version == 3)
  197.                                                 {
  198.                                                     int    Serial = 0,
  199.                                                         i;
  200.  
  201.                                                         /* Calculate the serial number. */
  202.  
  203.                                                     for(i = 0 ; i < 6 ; i++)
  204.                                                     {
  205.                                                         Serial *= 10;
  206.                                                         Serial += GameHeader . serial_no[i] - '0';
  207.                                                     }
  208.  
  209.                                                         /* Try to find a corresponding
  210.                                                          * game in the list.
  211.                                                          */
  212.  
  213.                                                     for(i = 0 ; SerialNumbers[i][SERIAL_INDEX] != -1 ; i++)
  214.                                                     {
  215.                                                             /* Do the serial numbers match? */
  216.  
  217.                                                         if(Serial == SerialNumbers[i][SERIAL_NUMBER] && GameHeader . release == SerialNumbers[i][SERIAL_RELEASE])
  218.                                                         {
  219.                                                                 /* Add the game file to the list. */
  220.  
  221.                                                             GameAdd(GameList,SerialNumbers[i][SERIAL_INDEX],TempBuffer);
  222.  
  223.                                                             break;
  224.                                                         }
  225.                                                     }
  226.                                                 }
  227.                                             }
  228.  
  229.                                                 /* Close the game file. */
  230.  
  231.                                             fclose(GameFile);
  232.                                         }
  233.                                     }
  234.                                 }
  235.                             }
  236.                         }
  237.                     }
  238.                 }
  239.             }
  240.             else
  241.                 break;
  242.         }
  243.         while(DevProc && (DevProc -> dvp_Flags & DVPF_ASSIGN));
  244.  
  245.             /* Free the fileinfo data. */
  246.  
  247.         FreeDosObject(DOS_FIB,FileInfo);
  248.     }
  249.  
  250.         /* Reset the default filesystem task. */
  251.  
  252.     SetFileSysTask(FileSysTask);
  253.  
  254.         /* Free device process data. */
  255.  
  256.     if(DevProc)
  257.         FreeDeviceProc(DevProc);
  258. }
  259.  
  260.     /* GameGetNodeName(struct List *List,int Offset):
  261.      *
  262.      *    Scan the list, returning the nth node.
  263.      */
  264.  
  265. char *
  266. GameGetNodeName(struct List *List,const int Offset)
  267. {
  268.     struct GameNode    *Node = (struct GameNode *)List -> lh_Head;
  269.     int         i;
  270.  
  271.     for(i = 0 ; Node -> gn_Node . ln_Succ && i < Offset ; i++)
  272.         Node = (struct GameNode *)Node -> gn_Node . ln_Succ;
  273.  
  274.     return(Node -> gn_FileName);
  275. }
  276.  
  277.     /* GameFreeList(struct List *List):
  278.      *
  279.      *    Free the contents of the list,
  280.      *    including the list itself.
  281.      */
  282.  
  283. VOID
  284. GameFreeList(struct List *List)
  285. {
  286.     struct Node    *Node,
  287.             *Next;
  288.  
  289.     Node = List -> lh_Head;
  290.  
  291.     while(Next = Node -> ln_Succ)
  292.     {
  293.         FreeVec(Node);
  294.  
  295.         Node = Next;
  296.     }
  297.  
  298.     FreeVec(List);
  299. }
  300.  
  301.     /* GameIsAssign(const STRPTR Name):
  302.      *
  303.      *    Check to see if a device name passed in
  304.      *    actually refers to an assignment.
  305.      */
  306.  
  307. Bool
  308. GameIsAssign(const STRPTR Name)
  309. {
  310.     WORD NameLen    = strlen(Name) - 1;
  311.     Bool Result    = FALSE;
  312.  
  313.         /* Does it end with a colon? */
  314.  
  315.     if(Name[NameLen] == ':')
  316.     {
  317.         struct DosList *DosList;
  318.  
  319.             /* Lock the list of assignments for reading. */
  320.  
  321.         if(DosList = AttemptLockDosList(LDF_ASSIGNS | LDF_READ))
  322.         {
  323.             STRPTR AssignName;
  324.  
  325.                 /* Scan the list... */
  326.  
  327.             while(DosList = NextDosEntry(DosList,LDF_ASSIGNS))
  328.             {
  329.                     /* Convert the name from icky
  330.                      * BCPL to `C' style string.
  331.                      */
  332.  
  333.                 AssignName = (STRPTR)BADDR(DosList -> dol_Name);
  334.  
  335.                     /* Does the name length match? */
  336.  
  337.                 if(AssignName[0] == NameLen)
  338.                 {
  339.                         /* Does the name itself match? */
  340.  
  341.                     if(!Strnicmp(&AssignName[1],Name,NameLen))
  342.                     {
  343.                         Result = TRUE;
  344.  
  345.                         break;
  346.                     }
  347.                 }
  348.             }
  349.  
  350.                 /* Unlock the list of assignments. */
  351.  
  352.             UnLockDosList(LDF_ASSIGNS | LDF_READ);
  353.         }
  354.     }
  355.  
  356.         /* Return the result. */
  357.  
  358.     return(Result);
  359. }
  360.  
  361.     /* GameBuildList(const char *Pattern):
  362.      *
  363.      *    Build a list of infocom games whose names
  364.      *    match a certain pattern.
  365.      */
  366.  
  367. struct List *
  368. GameBuildList(const char *Pattern)
  369. {
  370.     APTR         OldPtr = ThisProcess -> pr_WindowPtr;
  371.     struct List    *GameList = NULL;
  372.     BPTR         NewDir;
  373.  
  374.         /* No DOS requesters, please! */
  375.  
  376.     ThisProcess -> pr_WindowPtr = (APTR)-1;
  377.  
  378.         /* Is the assignment present? */
  379.  
  380.     if(NewDir = Lock("Infocom:",ACCESS_READ))
  381.     {
  382.             /* Allocate space for the new list. */
  383.  
  384.         if(GameList = (struct List *)AllocVec(sizeof(struct List),MEMF_ANY))
  385.         {
  386.                 /* Initialize the list. */
  387.  
  388.             NewList(GameList);
  389.  
  390.                 /* Will we have to deal with
  391.                  * an assignment or a volume?
  392.                  */
  393.  
  394.             if(GameIsAssign("Infocom:"))
  395.                 GameMultiScan(GameList,Pattern);
  396.             else
  397.             {
  398.                 struct FileInfoBlock    *FileInfo;
  399.                 header_t         GameHeader;
  400.  
  401.                     /* Allocate space for two fileinfo blocks. */
  402.  
  403.                 if(FileInfo = (struct FileInfoBlock *)AllocDosObjectTags(DOS_FIB,TAG_DONE))
  404.                 {
  405.                         /* Take a look at the assignment. */
  406.  
  407.                     if(Examine(NewDir,FileInfo))
  408.                     {
  409.                             /* Does it really refer to a directory? */
  410.  
  411.                         if(FileInfo -> fib_DirEntryType > 0)
  412.                         {
  413.                                 /* Examine the whole directory. */
  414.  
  415.                             while(ExNext(NewDir,FileInfo))
  416.                             {
  417.                                     /* Is it a file? */
  418.  
  419.                                 if(FileInfo -> fib_DirEntryType < 0)
  420.                                 {
  421.                                     if(GameMatch(FileInfo -> fib_FileName,Pattern))
  422.                                     {
  423.                                             /* Build a path to the story file,
  424.                                              * if present.
  425.                                              */
  426.  
  427.                                         strcpy(TempBuffer,"Infocom:");
  428.  
  429.                                         if(AddPart(TempBuffer,FileInfo -> fib_FileName,MAX_FILENAME_LENGTH))
  430.                                         {
  431.                                             FILE *GameFile;
  432.  
  433.                                                 /* Try to open the file for reading. */
  434.  
  435.                                             if(GameFile = fopen(TempBuffer,"rb"))
  436.                                             {
  437.                                                     /* Read the game file header. */
  438.  
  439.                                                 if(fread(&GameHeader,sizeof(header_t),1,GameFile) == 1)
  440.                                                 {
  441.                                                         /* Is it a type 3 game? */
  442.  
  443.                                                     if(GameHeader . z_version == 3)
  444.                                                     {
  445.                                                         int    Serial = 0,
  446.                                                             i;
  447.  
  448.                                                             /* Calculate the serial number. */
  449.  
  450.                                                         for(i = 0 ; i < 6 ; i++)
  451.                                                         {
  452.                                                             Serial *= 10;
  453.                                                             Serial += GameHeader . serial_no[i] - '0';
  454.                                                         }
  455.  
  456.                                                             /* Try to find a corresponding
  457.                                                              * game in the list.
  458.                                                              */
  459.  
  460.                                                         for(i = 0 ; SerialNumbers[i][SERIAL_INDEX] != -1 ; i++)
  461.                                                         {
  462.                                                                 /* Do the serial numbers match? */
  463.  
  464.                                                             if(Serial == SerialNumbers[i][SERIAL_NUMBER] && GameHeader . release == SerialNumbers[i][SERIAL_RELEASE])
  465.                                                             {
  466.                                                                     /* Add the game file to the list. */
  467.  
  468.                                                                 GameAdd(GameList,SerialNumbers[i][SERIAL_INDEX],TempBuffer);
  469.  
  470.                                                                 break;
  471.                                                             }
  472.                                                         }
  473.                                                     }
  474.                                                 }
  475.  
  476.                                                     /* Close the game file. */
  477.  
  478.                                                 fclose(GameFile);
  479.                                             }
  480.                                         }
  481.                                     }
  482.                                 }
  483.                             }
  484.                         }
  485.                     }
  486.  
  487.                         /* Free the fileinfo data. */
  488.  
  489.                     FreeDosObject(DOS_FIB,FileInfo);
  490.                 }
  491.             }
  492.  
  493.                 /* Does the list contain any entries? */
  494.  
  495.             if(!GameList -> lh_Head -> ln_Succ)
  496.             {
  497.                 FreeVec(GameList);
  498.  
  499.                 GameList = NULL;
  500.             }
  501.         }
  502.  
  503.             /* Release the lock on the directory. */
  504.  
  505.         UnLock(NewDir);
  506.     }
  507.  
  508.         /* Enable DOS requesters again. */
  509.  
  510.     ThisProcess -> pr_WindowPtr = OldPtr;
  511.  
  512.         /* Return the game file list. */
  513.  
  514.     return(GameList);
  515. }
  516.  
  517.     /* GameGetStoryName():
  518.      *
  519.      *    Ask the user for a story game file name.
  520.      */
  521.  
  522. char *
  523. GameGetStoryName(const char *Pattern,const struct Window *Window)
  524. {
  525.     struct FileRequester    *StoryRequest;
  526.     char            *Result = NULL;
  527.  
  528.         /* Get the current directory name. */
  529.  
  530.     if(!GetCurrentDirName(TempBuffer,MAX_FILENAME_LENGTH))
  531.         TempBuffer[0] = 0;
  532.  
  533.         /* Allocate the file requester. */
  534.  
  535.     if(StoryRequest = AllocAslRequestTags(ASL_FileRequest,
  536.         ASL_Hail,                "Select a story file",
  537.         ASL_OKText,                "Select",
  538.         ASL_File,                "Story.Data",
  539.         ASL_Dir,                TempBuffer,
  540.         ASL_Pattern,                Pattern,
  541.         ASL_FuncFlags,                FILF_PATGAD,
  542.         Window ? ASL_Window : TAG_IGNORE,    Window,
  543.     TAG_DONE))
  544.     {
  545.             /* Loop until a result is found. */
  546.  
  547.         while(!Result)
  548.         {
  549.                 /* Ask the user for a file name. */
  550.  
  551.             if(AslRequestTags(StoryRequest,TAG_DONE))
  552.             {
  553.                     /* Did we get a file name? */
  554.  
  555.                 if(StoryRequest -> rf_File[0])
  556.                 {
  557.                         /* Copy the directory name. */
  558.  
  559.                     strcpy(TempBuffer,StoryRequest -> rf_Dir);
  560.  
  561.                         /* Build the full path name. */
  562.  
  563.                     if(AddPart(TempBuffer,StoryRequest -> rf_File,MAX_FILENAME_LENGTH))
  564.                     {
  565.                             /* Is it a valid story game file? */
  566.  
  567.                         if(ConCheckStory(TempBuffer))
  568.                             Result = TempBuffer;
  569.                         else
  570.                             ConShowRequest(Window,"File \"%s\" is not a valid story game file.","Continue",StoryRequest -> rf_File);
  571.                     }
  572.                     else
  573.                         ConShowRequest(Window,"Error building path name!","Continue");
  574.                 }
  575.                 else
  576.                     break;
  577.             }
  578.             else
  579.                 break;
  580.         }
  581.  
  582.         FreeAslRequest(StoryRequest);
  583.     }
  584.  
  585.     return(Result);
  586. }
  587.  
  588.     /* GameCentreWindow():
  589.      *
  590.      *    Adjust coordinates of a window to be opened,
  591.      *    so that it will come up right under the mouse
  592.      *    pointer.
  593.      */
  594.  
  595. VOID
  596. GameCentreWindow(const struct Screen *Screen,const WORD WindowWidth,const WORD WindowHeight,WORD *LeftEdge,WORD *TopEdge)
  597. {
  598.     *LeftEdge    = Screen -> MouseX - WindowWidth / 2;
  599.     *TopEdge    = Screen -> MouseY - WindowHeight / 2;
  600.  
  601.     while((*LeftEdge) + WindowWidth > Screen -> Width)
  602.         (*LeftEdge)--;
  603.  
  604.     while((*LeftEdge) < 0)
  605.         (*LeftEdge)++;
  606.  
  607.     while((*TopEdge) + WindowHeight > Screen -> Height)
  608.         (*TopEdge)--;
  609.  
  610.     while((*TopEdge) < 0)
  611.         (*TopEdge)++;
  612. }
  613.  
  614.     /* GameCreateGadgets():
  615.      *
  616.      *    Create list view and button for the
  617.      *    game list selection window.
  618.      */
  619.  
  620. struct Gadget *
  621. GameCreateGadgets(struct Gadget **GadgetArray,struct Gadget **GadgetList,const APTR VisualInfo,const struct List *Labels,const struct Screen *Screen,WORD *WindowWidth,WORD *WindowHeight)
  622. {
  623.     STATIC STRPTR GadgetLabels[] =
  624.     {
  625.         "Choose a story",
  626.         "Select a story file...",
  627.         "Cancel"
  628.     };
  629.  
  630.     struct Gadget        *Gadget;
  631.     struct NewGadget     NewGadget;
  632.     UWORD             Counter,
  633.                  Lines = 0;
  634.     struct Node        *Node,
  635.                 *Next;
  636.     UWORD             MaxWidth,
  637.                  ListWidth    = 0,
  638.                  ButtonWidth    = 0,
  639.                  Width;
  640.     int             i;
  641.  
  642.         /* Determine the longest label string. */
  643.  
  644.     Node = Labels -> lh_Head;
  645.  
  646.     while(Next = Node -> ln_Succ)
  647.     {
  648.         Lines++;
  649.  
  650.         if((Width = TextLength((struct RastPort *)&Screen -> RastPort,Node -> ln_Name,strlen(Node -> ln_Name))) > ListWidth)
  651.             ListWidth = Width;
  652.  
  653.         Node = Next;
  654.     }
  655.  
  656.         /* Is the button label text longer than
  657.          * all the list labels?
  658.          */
  659.  
  660.     if((Width = TextLength((struct RastPort *)&Screen -> RastPort,GadgetLabels[GAMEGAD_LIST],strlen(GadgetLabels[GAMEGAD_LIST]))) > ListWidth)
  661.         ListWidth = Width;
  662.  
  663.         /* Determine the longest button label. */
  664.  
  665.     for(i = GAMEGAD_SELECT ; i <= GAMEGAD_CANCEL ; i++)
  666.     {
  667.         if((Width = TextLength((struct RastPort *)&Screen -> RastPort,GadgetLabels[i],strlen(GadgetLabels[i]))) > ButtonWidth)
  668.             ButtonWidth = Width;
  669.     }
  670.  
  671.         /* Adjust the values. */
  672.  
  673.     ListWidth    = (4 + ListWidth + 4) + 16 + 8;
  674.     ButtonWidth    = 4 + ButtonWidth + 4;
  675.  
  676.         /* Are the two buttons wider than the list? */
  677.  
  678.     if(2 * ButtonWidth + INTERWIDTH > ListWidth)
  679.         MaxWidth = 2 * ButtonWidth + INTERWIDTH;
  680.     else
  681.     {
  682.         MaxWidth    = ListWidth;
  683.         ButtonWidth    = (ListWidth - INTERWIDTH) / 2;
  684.     }
  685.  
  686.         /* Loop until the list fits on the screen. */
  687.  
  688.     FOREVER
  689.     {
  690.             /* Zero the template. */
  691.  
  692.         memset(&NewGadget,0,sizeof(struct NewGadget));
  693.  
  694.             /* Clear the gadget counter. */
  695.  
  696.         Counter = 0;
  697.  
  698.             /* Create gadget list context. */
  699.  
  700.         if(Gadget = CreateContext(GadgetList))
  701.         {
  702.                 /* Set up for gadget creation. */
  703.  
  704.             NewGadget . ng_GadgetText    = GadgetLabels[Counter];
  705.             NewGadget . ng_GadgetID        = Counter;
  706.             NewGadget . ng_TextAttr        = Screen -> Font;
  707.             NewGadget . ng_VisualInfo    = VisualInfo;
  708.             NewGadget . ng_GadgetID        = Counter;
  709.             NewGadget . ng_Flags        = PLACETEXT_ABOVE;
  710.             NewGadget . ng_LeftEdge        = Screen -> WBorLeft + INTERWIDTH;
  711.             NewGadget . ng_TopEdge        = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + INTERHEIGHT + Screen -> Font -> ta_YSize + INTERHEIGHT;
  712.             NewGadget . ng_Width        = MaxWidth;
  713.             NewGadget . ng_Height        = 4 + Lines * Screen -> Font -> ta_YSize + 4;
  714.  
  715.                 /* Create the list view. */
  716.  
  717.             GadgetArray[Counter++] = Gadget = CreateGadget(LISTVIEW_KIND,Gadget,&NewGadget,
  718.                 GTLV_Labels,Labels,
  719.             TAG_DONE);
  720.  
  721.             NewGadget . ng_GadgetText    = GadgetLabels[Counter];
  722.             NewGadget . ng_GadgetID        = Counter;
  723.             NewGadget . ng_Flags        = NULL;
  724.             NewGadget . ng_TopEdge        = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT;
  725.             NewGadget . ng_Width        = ButtonWidth;
  726.             NewGadget . ng_Height        = 2 + Screen -> Font -> ta_YSize + 2;
  727.  
  728.                 /* Create the left button. */
  729.  
  730.             GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,TAG_DONE);
  731.  
  732.             NewGadget . ng_GadgetText    = GadgetLabels[Counter];
  733.             NewGadget . ng_GadgetID        = Counter;
  734.             NewGadget . ng_Flags        = NULL;
  735.             NewGadget . ng_LeftEdge        = NewGadget . ng_LeftEdge + NewGadget . ng_Width + INTERWIDTH;
  736.  
  737.                 /* Create the right button. */
  738.  
  739.             GadgetArray[Counter] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,TAG_DONE);
  740.  
  741.                 /* Adjust window dimensions. */
  742.  
  743.             *WindowWidth    = Screen -> WBorLeft + INTERWIDTH + MaxWidth + INTERWIDTH + Screen -> WBorRight;
  744.             *WindowHeight    = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT + Screen -> WBorBottom;
  745.  
  746.                 /* Is the window larger than the screen? */
  747.  
  748.             if(*WindowHeight > Screen -> Height)
  749.             {
  750.                     /* Free gadget list. */
  751.  
  752.                 FreeGadgets(*GadgetList);
  753.  
  754.                 *GadgetList = NULL;
  755.  
  756.                     /* If possible, reduce the list
  757.                      * by another line. If this turns
  758.                      * out to be too much, just fail.
  759.                      */
  760.  
  761.                 if(Lines > 2)
  762.                     Lines--;
  763.                 else
  764.                     return(NULL);
  765.             }
  766.             else
  767.                 return(Gadget);
  768.         }
  769.     }
  770. }
  771.  
  772.     /* GameSelect(char *Name):
  773.      *
  774.      *    Select a game file either by list or by file requester.
  775.      */
  776.  
  777. Bool
  778. GameSelect(char *Name)
  779. {
  780.     struct Window    *Window;
  781.     struct List    *GameList;
  782.     WORD         WindowWidth,
  783.              WindowHeight;
  784.     struct Gadget    *GadgetList,
  785.             *GadgetArray[GAMEGAD_CANCEL + 1];
  786.     Bool         Result = FALSE;
  787.     struct Screen    *Screen;
  788.     WORD         Left,
  789.              Top;
  790.     char         PatternBuffer[MAX_FILENAME_LENGTH];
  791.     int         i;
  792.  
  793.         /* Is more than a single filename extension available? */
  794.  
  795.     if(StoryExtensions[1])
  796.     {
  797.             /* Start with a standard pattern header. */
  798.  
  799.         strcpy(PatternBuffer,"#?(");
  800.  
  801.             /* Add the alternatives. */
  802.  
  803.         for(i = 0 ; StoryExtensions[i] ; i++)
  804.         {
  805.                 /* No extension? Clear the
  806.                  * pattern and exit.
  807.                  */
  808.  
  809.             if(!StoryExtensions[i][0])
  810.             {
  811.                 PatternBuffer[0] = 0;
  812.  
  813.                 break;
  814.             }
  815.             else
  816.             {
  817.                 if(i)
  818.                     strcat(PatternBuffer,"|");
  819.  
  820.                 strcat(PatternBuffer,StoryExtensions[i]);
  821.             }
  822.         }
  823.  
  824.             /* Finish the pattern. */
  825.  
  826.         if(PatternBuffer[0])
  827.             strcat(PatternBuffer,")");
  828.         else
  829.             strcpy(PatternBuffer,"~(#?.info)");
  830.     }
  831.     else
  832.     {
  833.             /* That one's simple: just a standard pattern
  834.              * plus the extension.
  835.              */
  836.  
  837.         strcpy(PatternBuffer,"#?");
  838.         strcat(PatternBuffer,StoryExtensions[0]);
  839.     }
  840.  
  841.         /* Obtain a lock on the default public screen. */
  842.  
  843.     if(Screen = LockPubScreen(NULL))
  844.     {
  845.             /* Build a list of game files. */
  846.  
  847.         if(GameList = GameBuildList(PatternBuffer))
  848.         {
  849.                 /* Is there only one entry in the list? */
  850.  
  851.             if(!GameList -> lh_Head -> ln_Succ -> ln_Succ)
  852.             {
  853.                 struct GameNode *Node = (struct GameNode *)GameList -> lh_Head;
  854.  
  855.                 strcpy(Name,Node -> gn_FileName);
  856.  
  857.                 Result = TRUE;
  858.             }
  859.             else
  860.             {
  861.                 APTR VisualInfo;
  862.  
  863.                     /* Obtain visual information. */
  864.  
  865.                 if(VisualInfo = GetVisualInfo(Screen,TAG_DONE))
  866.                 {
  867.                         /* Create gadget list. */
  868.  
  869.                     if(GameCreateGadgets(GadgetArray,&GadgetList,VisualInfo,GameList,Screen,&WindowWidth,&WindowHeight))
  870.                     {
  871.                             /* Centre the window under the mouse pointer. */
  872.  
  873.                         GameCentreWindow(Screen,WindowWidth,WindowHeight,&Left,&Top);
  874.  
  875.                             /* Open the window. */
  876.  
  877.                         if(Window = OpenWindowTags(NULL,
  878.                             WA_Width,    WindowWidth,
  879.                             WA_Height,    WindowHeight,
  880.                             WA_Left,    Left,
  881.                             WA_Top,        Top,
  882.                             WA_Title,    "Infocom games",
  883.                             WA_RMBTrap,    TRUE,
  884.                             WA_DepthGadget,    TRUE,
  885.                             WA_CloseGadget,    TRUE,
  886.                             WA_DragBar,    TRUE,
  887.                             WA_Activate,    TRUE,
  888.                             WA_CustomScreen,Screen,
  889.                             WA_IDCMP,    IDCMP_CLOSEWINDOW | BUTTONIDCMP | LISTVIEWIDCMP,
  890.                         TAG_DONE))
  891.                         {
  892.                             STATIC struct Requester     BlockRequest;
  893.  
  894.                             struct IntuiMessage    *Massage;
  895.                             ULONG             Class,
  896.                                          Code;
  897.                             struct Gadget        *Gadget;
  898.                             char            *Buffer;
  899.                             Bool             Terminated = FALSE;
  900.  
  901.                                 /* Add and draw the gadget list. */
  902.  
  903.                             AddGList(Window,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
  904.                             RefreshGList(GadgetList,Window,NULL,(UWORD)-1);
  905.                             GT_RefreshWindow(Window,NULL);
  906.  
  907.                                 /* Loop, waiting for input. */
  908.  
  909.                             do
  910.                             {
  911.                                     /* Wait for it... */
  912.  
  913.                                 WaitPort(Window -> UserPort);
  914.  
  915.                                     /* Process incoming messages. */
  916.  
  917.                                 while(Massage = GT_GetIMsg(Window -> UserPort))
  918.                                 {
  919.                                         /* Pick up the message data. */
  920.  
  921.                                     Class    = Massage -> Class;
  922.                                     Code    = Massage -> Code;
  923.                                     Gadget    = (struct Gadget *)Massage -> IAddress;
  924.  
  925.                                         /* Reply the message to the sender. */
  926.  
  927.                                     GT_ReplyIMsg(Massage);
  928.  
  929.                                         /* Process the message class. */
  930.  
  931.                                     switch(Class)
  932.                                     {
  933.                                             /* Window is to be closed? */
  934.  
  935.                                         case IDCMP_CLOSEWINDOW:        Terminated = TRUE;
  936.                                                         break;
  937.  
  938.                                             /* A button was pressed or a list
  939.                                              * item was selected.
  940.                                              */
  941.  
  942.                                         case IDCMP_GADGETUP:    switch(Gadget -> GadgetID)
  943.                                                     {
  944.                                                             /* A list entry was selected,
  945.                                                              * use the corresponding game
  946.                                                              * file name.
  947.                                                              */
  948.  
  949.                                                         case GAMEGAD_LIST:    strcpy(Name,GameGetNodeName(GameList,Code));
  950.  
  951.                                                                     Result = Terminated = TRUE;
  952.  
  953.                                                                     break;
  954.  
  955.                                                             /* Select a game file. */
  956.  
  957.                                                         case GAMEGAD_SELECT:    memset(&BlockRequest,0,sizeof(struct Requester));
  958.  
  959.                                                                         /* Block window output. */
  960.  
  961.                                                                     Request(&BlockRequest,Window);
  962.  
  963.                                                                         /* Set the wait pointer. */
  964.  
  965.                                                                     WaitPointer(Window);
  966.  
  967.                                                                         /* Ask the user for a file name. */
  968.  
  969.                                                                     if(Buffer = GameGetStoryName(PatternBuffer,Window))
  970.                                                                     {
  971.                                                                         strcpy(Name,Buffer);
  972.  
  973.                                                                         Result = Terminated = TRUE;
  974.                                                                     }
  975.  
  976.                                                                         /* Remove the wait pointer. */
  977.  
  978.                                                                     ClearPointer(Window);
  979.  
  980.                                                                         /* Remove the blocking requester. */
  981.  
  982.                                                                     EndRequest(&BlockRequest,Window);
  983.  
  984.                                                                     break;
  985.  
  986.                                                             /* Cancel selection. */
  987.  
  988.                                                         case GAMEGAD_CANCEL:    Terminated = TRUE;
  989.  
  990.                                                                     break;
  991.                                                     }
  992.  
  993.                                                     break;
  994.                                     }
  995.                                 }
  996.                             }
  997.                             while(!Terminated);
  998.  
  999.                                 /* Close the window. */
  1000.  
  1001.                             CloseWindow(Window);
  1002.                         }
  1003.  
  1004.                             /* Free the gadget data. */
  1005.  
  1006.                         FreeGadgets(GadgetList);
  1007.                     }
  1008.  
  1009.                         /* Relese the visual information data. */
  1010.  
  1011.                     FreeVisualInfo(VisualInfo);
  1012.                 }
  1013.             }
  1014.  
  1015.                 /* Free the game file list. */
  1016.  
  1017.             GameFreeList(GameList);
  1018.         }
  1019.         else
  1020.         {
  1021.             char *Buffer;
  1022.  
  1023.                 /* Ask the user for a file name. */
  1024.  
  1025.             if(Buffer = GameGetStoryName(PatternBuffer,NULL))
  1026.             {
  1027.                 strcpy(Name,Buffer);
  1028.  
  1029.                 Result = TRUE;
  1030.             }
  1031.         }
  1032.  
  1033.             /* Release the lock on the default
  1034.              * public screen.
  1035.              */
  1036.  
  1037.         UnlockPubScreen(NULL,Screen);
  1038.     }
  1039.  
  1040.         /* Return the result. */
  1041.  
  1042.     return(Result);
  1043. }
  1044.